package org.example.toy;


import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;


//客户端的小玩具 用来和服务端交互 内含selector channel
public class ClientToy {
    private int port = 8080;

    public ClientToy(int port) {
        this.port = port;
    }

    public ClientToy() {
    }

    public  void start() throws Exception {
        Selector selector = Selector.open();

        //创建小channel 并连接
        SocketChannel socketChannel = SocketChannel.open();
        socketChannel.configureBlocking( false);
        //连接
        socketChannel.connect(new InetSocketAddress("localhost", port));

        socketChannel.register(selector, SelectionKey.OP_CONNECT);


        while (true) {
            // 4. 阻塞等待Selector事件
            selector.select();

            // 5. 处理选择的事件
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
            while (iterator.hasNext()) {
                SelectionKey key = iterator.next();
                iterator.remove(); // 必须移除，防止重复处理

                // 6. 处理连接事件
                if (key.isConnectable()) {
                    onConnect(socketChannel,key);
                }

                // 7. 处理写事件
                if (key.isWritable()) {
                    onWrite(socketChannel, key);
                }

                //读事件
                if (key.isReadable()){
                    onRead(socketChannel,key);
                }

            }
        }

    }

    public static void main(String[] args) throws Exception {
        Selector selector = Selector.open();

        //创建小channel 并连接
        SocketChannel socketChannel = SocketChannel.open();
        socketChannel.configureBlocking( false);
        //连接
        socketChannel.connect(new InetSocketAddress("localhost", 8080));

        socketChannel.register(selector, SelectionKey.OP_CONNECT);


        while (true) {
            // 4. 阻塞等待Selector事件
            selector.select();

            // 5. 处理选择的事件
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
            while (iterator.hasNext()) {
                SelectionKey key = iterator.next();
                iterator.remove(); // 必须移除，防止重复处理

                // 6. 处理连接事件
                if (key.isConnectable()) {
                    onConnect(socketChannel,key);
                }

                // 7. 处理写事件
                if (key.isWritable()) {
                    onWrite(socketChannel, key);
                }

                //读事件
                if (key.isReadable()){
                    onRead(socketChannel,key);
                }

            }
        }

    }

    private static void onRead(SocketChannel socketChannel, SelectionKey key) throws IOException {
        ByteBuffer allocate = ByteBuffer.allocate(1024);
        int read = socketChannel.read(allocate);
        if (read > 0) {
            System.out.println("收到服务器数据：" + new String(allocate.array(), 0, read));
        }

    }

    // 处理连接事件
    private static void onConnect(SocketChannel socketChannel, SelectionKey key) throws IOException {
        //如果有未完成的连接 则连接
        if (socketChannel.isConnectionPending()) {
            socketChannel.finishConnect(); // 完成连接
            System.out.println("连接成功");
        }

        //这个channel 修改注册事件
        key.interestOps(SelectionKey.OP_WRITE | SelectionKey.OP_READ);
    }

    // 处理写操作
    private static void onWrite(SocketChannel socketChannel, SelectionKey key) throws IOException {

        System.out.println("开始写入数据");
        //先看有没有未完成的数据
        ByteBuffer buffer = (ByteBuffer) key.attachment();

        if (buffer == null) {
            // 没有未完成的写数据，准备新数据
            String message = "Hello from client!*";
            buffer = ByteBuffer.wrap(message.getBytes());
        }

        // 写入数据
        int written = socketChannel.write(buffer);

        System.out.println("已写入：" + written + " 字节 客户端线程" +Thread.currentThread().getName());

        if (buffer.hasRemaining()) {
            // 写不完，继续监听写事件，保存剩余数据
            key.attach(buffer);
        }
        else {
            // 写完，取消监听写事件
            key.interestOps(SelectionKey.OP_READ);
            key.attach(null);
        }

        System.out.println("数据已写入到服务器");
    }

}
